package com.atguigu.interview.study.juc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author gcq
 * @Create 2020-12-07
 * 要求t1线程等待3秒钟，3秒钟后t2线程唤醒t1线程继续工作
 * 以下异常情况：
 * 2、wait和notify方法，两个去掉同步代码块后查看运行效果
 *      2.1 异常情况
 *      Exception in thread "t1" java.lang.IllegalMonitorStateException at java.lang.Object.wait(Native Method)
 *      java.lang.IllegalMonitorStateException at java.lang.Object.notify(Native Method)
 *      2.2 结论
 *      Object类中的wait、notify、notifyAll用于线程等待和唤醒的方法，必须包含在synchronized内部执行，必须用到关键字synchronized
 *
 */
public class LockSupportDemo {
    static Object objectLock = new Object();
    static Lock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Thread t1 = new Thread(() ->{
            // 暂停一会线程
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(Thread.currentThread().getName() + "\t" + System.currentTimeMillis());
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + "---被叫醒");
        },"t1");
        t1.start();

        // 暂停一会线程
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

        LockSupport.unpark(t1);
        System.out.println(Thread.currentThread().getName() + "\t" + System.currentTimeMillis() + "----unpark over");
    }

    private static void lockAwaitSignal() {
        new Thread(() -> {
            // 暂停一会线程
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName()+"\t" + "come in");
                try {
                    condition.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        },"A").start();


        new Thread(() -> {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName()+"\t" + "---通知");
                try {
                    condition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        },"B").start();
    }

    /**
     * synchronized 的 wait notify方法
     */
    private static void synchronizedWaitNotify() {
        new Thread(() -> {
            synchronized (objectLock) {
            // 暂停一会线程
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
                System.out.println(Thread.currentThread().getName() + "\t" + "-----------come in");
                try {
                    objectLock.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒");
            }
        },"A").start();

        new Thread(() ->{
             synchronized (objectLock) {
                 objectLock.notify();
                 System.out.println(Thread.currentThread().getName() + "\t" + "----通知");
             }
        },"t1").start();
    }
}